package middlewares

import (
	"ginjwt/config"
	"ginjwt/models"
	"ginjwt/utils"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

// 判断用户是否登录 - 请求头是否携带认证信息且正确
func AuthMiddleware() gin.HandlerFunc {

	return func(c *gin.Context) {
		conf := config.GetConfig()
		authHeader := c.GetHeader("Authorization")

		// 如果用户发过来的请求头上没有Authorization字段，返回401错误
		// 相应头中包含WWW-Authenticate字段,提醒前端
		if authHeader == "" {
			// 相应头中应该有WWWW-Authenticate: Bearer realm="api"
			c.Header("WWW-Authenticate", "Bearer realm=\"api\"")
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"detail": "没有提供认证信息",
			})
			return
		}

		// 处理用户传过来的Authorization请求头信息
		authHeaderSlice := strings.Split(authHeader, " ")
		authHeaderType := authHeaderSlice[0]
		tokenString := strings.Join(authHeaderSlice[1:], "")
		// 去掉首尾空格
		tokenString = strings.Trim(tokenString, " ")

		// 只支持Bearer认证头部类型,下面使用jwt发送请求会报错
		// curl -i -H "Authorization: jwt xx" http://localhost:8080/api/v1/protected/
		// 返回值: {"detail":"不支持jwt token,只支持Bearer token"}
		if authHeaderType != conf.GetString("TOKEN.AUTH_HEADER_TYPE") {
			c.Header("WWW-Authenticate", "Bearer realm=\"api\"")
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"detail": "不支持" + authHeaderType + " token,只支持Bearer token",
			})
			return
		}

		token, err := utils.ValidateToken(tokenString)

		// 注意这里token可能为nil
		if token != nil && token.Valid {

			claims := token.Claims.(*models.AuthClaims)

			// TODO：获得用户信息后做什么
			// getUser函数 - 从数据库中获取数据
			// fmt.Printf("claims: %v\n", claims.UserId)

			// token类型不匹配
			if claims.TokenType != conf.GetString("TOKEN.ACCESS_TOKEN_TYPE") {
				c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"detail": "Token类型不匹配"})
				return
			}

			// TODO: 需要匹配数据库中的用户名
			if claims.UserId != conf.GetString("AUTH.USERNAME") {
				c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"detail": "无效Token"})
				return
			}

		} else {
			// 这里token信息可能已经过期，或者不正确（如被篡改)
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"detail": err.Error()})
			return
		}

		// 如果前面都没有abort,执行下一个handler函数
		c.Next()
	}
}
